package com.yunji.cabinet.device;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONObject;
import com.yunji.cabinet.domain.DeviceEventDO;
import com.yunji.cabinet.dto.device.DeviceCommandDTO;
import com.yunji.cabinet.dto.device.DeviceEventDTO;
import com.yunji.cabinet.dto.device.UpgradeCommandDTO;
import com.yunji.cabinet.service.impl.DeviceService;
import com.yunji.common.base.response.Response;
import com.yunji.common.cache.LockUtil;
import com.yunji.common.exception.device.DeviceErrorEnum;
import com.yunji.common.exception.device.DeviceException;
import com.yunji.common.utils.JsonUtil;
import com.yunji.common.utils.spring.SpringUtils;
import com.yunji.coffee.entity.bo.CommonDeviceInfoBO;
import com.yunji.coffee.entity.dto.WipeDeviceInfoDTO;
import com.yunji.order.dto.OrderOrdinalDTO;
import com.yunji.system.context.SystemUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import java.util.Date;
import java.util.List;
/**
 * @author : peter-zhu
 * @date : 2025/1/14 17:13
 * @description : TODO
 **/
public abstract class DeviceCommandEngine {

    private static final Logger log = LoggerFactory.getLogger(DeviceCommandEngine.class);
    private static String DEVICE_URI;

    @Value("${device.url:''}")
    public void setCommandUrl(String deviceUri) {
        DEVICE_URI = deviceUri;
    }

//    public static Integer getRssi(String imei) {
//        DeviceInfoDTO newest = DeviceSpinService.getNewest(imei, ContainerTypeEnum.COFFEE.name());
//        if (newest != null)
//            return newest.getRssi();
//        else
//            throw new DeviceException(DeviceErrorEnum.CHECKED_202509, imei);
//    }

    public abstract String getTypeCode();

    public abstract Integer getRssi(String imei);

    public abstract List<Integer> topInfraredTest(String imei);

    public abstract CommonDeviceInfoBO getDeviceInfo(DeviceEventDO data);

    // 数量
    public abstract List<OrderOrdinalDTO> getProductNums(String imei);

    public abstract Boolean shippingTest(String imei);

    // 补货门是否关闭
//    public  boolean isLock(String imei) {
//        return false;
//    }

    public abstract boolean isLock(String imei);

    public static CommonDeviceInfoBO getDeviceInfo(DeviceEventDO data, String valueType) {
        return new CommonDeviceInfoBO(JsonUtil.readValue(data.getBeforeCmd(), ContainerTypeEnum.getClass(valueType)),
                JsonUtil.readValue(data.getAfterCmd(), ContainerTypeEnum.getClass(valueType)));
    }

    public static boolean executeCommand(DeviceCommandDTO commandDTO) {
        boolean lock = LockUtil.tryLock(commandDTO.getImei(), 30, 60);
        try {
            if (lock) {
                String jsonString = JsonUtil.toJsonString(commandDTO);
                String result = DeviceSignatureUtil.post(DEVICE_URI + "/command", jsonString);
                Response<?> response = JSONObject.parseObject(result, Response.class);
                boolean ack = response.isSuccess();
                if (!ack)
                    log.error("response.getMsg:{},cmd:{}", response.getMsg(), JsonUtil.toJsonString(commandDTO));
                return ack;
            }
        } finally {
            LockUtil.unlock(commandDTO.getImei());
        }
        return true;
    }

    public static int addEvent(DeviceEventDTO eventDTO) {
        int eventId = 0;
        try {
            DeviceService deviceService = SpringUtils.getBean(DeviceService.class);
            DeviceEventDO deviceEventDO = DeviceConvert.initDeviceEvent(eventDTO);
            Object info = DeviceInfoCache.getInfoByType(eventDTO.getCommandDTO().getImei(), deviceEventDO.getContainerType());
            if (info != null)
                deviceEventDO.setBeforeCmd(JsonUtil.toJsonString(info));
            deviceService.createEvent(deviceEventDO);
            eventId = deviceEventDO.getEventId().intValue();
        } catch (Exception e) {
            log.error("DeviceCommandEngine executeEvent errorData:{}", JsonUtil.toJsonString(eventDTO), e);
        }
        return eventId;
    }

    public static boolean executeEvent(DeviceEventDTO eventDTO) {
        DeviceCommandDTO commandDTO = eventDTO.getCommandDTO();
        commandDTO.setEventId(addEvent(eventDTO));
        return executeCommand(commandDTO);
    }

    public static boolean online(String imei) {
        boolean lock = LockUtil.tryLock(imei, 30, 60);
        try {
            if (lock) {
                return BooleanUtil.toBoolean(HttpUtil.get(DEVICE_URI + "/status/" + imei));
            }
        } finally {
            LockUtil.unlock(imei);
        }
        return false;
    }

    public static boolean addCycleOnline(String imei) {
        return BooleanUtil.toBoolean(DeviceSignatureUtil.get(DEVICE_URI + "/online/" + imei));
    }

    public static boolean addCycleOffline(String imei) {
        return BooleanUtil.toBoolean(DeviceSignatureUtil.get(DEVICE_URI + "/offline/" + imei));
    }


    public static void validateOnline(String imei) {
        if (!online(imei)) throw new DeviceException(DeviceErrorEnum.CHECKED_202504, imei);
    }

    // 补货门和出货们都必须关闭
//    public static boolean isLockAndClose(String imei) {
////        ICommonDeviceInfo info = DeviceInfoCache.getInfo(imei);
////        return info != null && info.getLockStatus() == 1;
//        return true;
//    }

    // 是否有货
    public abstract boolean tissueStatus(String imei, List<OrderOrdinalDTO> dtoList);

    // 是否正在升级
    public static boolean isUpGrading(String imei) {
        return SystemUtil.redisCache().hasKey(DeviceCacheCode.DEVICE_UPGRADE + imei);
    }

    // 电压是否足够
    public static boolean isVolt(String imei) {
        WipeDeviceInfoDTO info = (WipeDeviceInfoDTO) DeviceInfoCache.getInfo(imei);
        return info != null && info.getBattleLevel() > 30;
    }

    //升级
    public static boolean upgrade(UpgradeCommandDTO upgrade) {
        Assert.isTrue(!isUpGrading(upgrade.getImei()), "正在升级中");
        SystemUtil.redisCache().set(DeviceCacheCode.DEVICE_UPGRADE + upgrade.getImei(), new Date());
        upgrade.setEventId(-1);
        upgrade.setEvent(DeviceEventEnum.DEVICE_GRADE.name());
        upgrade.setCmd(DeviceCommandEnum.DEVICE_GRADE.name());
        String req = JsonUtil.toJsonString(upgrade);
        String result = DeviceSignatureUtil.post(DEVICE_URI + "/upgrade", req);
        Response<?> response = JSONObject.parseObject(result, Response.class);
        return response.isSuccess();
    }

    public static Object cabinetStatusList() {
        return DeviceSignatureUtil.get(DEVICE_URI + "/statusList");
    }

    public abstract Integer getProductCeiling(String typeCode, Long productId);

}
